﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using HugeFlow.CommandPattern.Interactivity;
using HugeFlow.ComponentModel;

namespace HugeFlow.CommandPattern
{
    /// <summary>
    /// Command pattern implementation (Static Command)
    /// </summary>
    public class StaticCommand 
    {
        #region Static
        /// <summary>
        /// Static constructor. Initialize static properties
        /// </summary>
        static StaticCommand()
        {
            CommandCache = new Dictionary<string, StaticCommand>();
        }

        /// <summary>
        /// Gets the command cache.
        /// </summary>
        /// <value>The command cache.</value>
        public static Dictionary<string, StaticCommand> CommandCache
        {
            get;
            private set;
        }

        /// <summary>
        /// Finds the command.
        /// </summary>
        /// <param name="commandName">The command name.</param>
        /// <returns>returns the command for a given commandName</returns>
        public static StaticCommand FindCommand(string commandName)
        {
            if (string.IsNullOrEmpty(commandName))
            {
                return null;
            }

            // Check from cache
            StaticCommand cmd = null;
            if (CommandCache.TryGetValue(commandName, out cmd))
            {
                return cmd;
            }


            return null;
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Command"/> class.
        /// </summary>
        /// <param name="commandName">The command name used for retreiving command in Xaml.</param>
        public StaticCommand(string commandName)
        {
            // Check from cache
            if (Runtime.IsBlend == false && CommandCache.ContainsKey(commandName))
            {
                throw new ArgumentException(string.Format(CommandPatternResource.SameNameCommand, commandName));
            }

            CommandName = commandName;
            CommandCache.Add(commandName, this);
        }

        #endregion Constructors

        #region Events

        /// <summary>
        /// Check if the specified command can be executed.
        /// </summary>
        public event EventHandler<CanExecuteEventArgs> CanExecuteChanged;

        /// <summary>
        /// Occurs when the command is executed.
        /// </summary>
        public event EventHandler<ExecutedEventArgs> Executed;

        #endregion Events

        #region Properties

        /// <summary>
        /// Gets the name of the command.
        /// </summary>
        public string CommandName
        {
            get;
            private set;
        }

        #endregion Properties

        #region Methods
        /// <summary>
        /// Executes the command
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        public void Execute(object parameter)
        {
            if (this.CanExecute(parameter))
            {
                if (this.Executed != null)
                {
                    ExecutedEventArgs e = new ExecutedEventArgs(this, parameter);
                    this.Executed(this, e);
                }
            }
        }

        /// <summary>
        /// Raises the can execute event.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        /// <returns>returns <c>true</c> if the command can be executed, otherwise <c>false</c>.</returns>
        public bool CanExecute(object parameter)
        {
            if (this.CanExecuteChanged != null)
            {
                CanExecuteEventArgs e = new CanExecuteEventArgs(this, parameter);
                this.CanExecuteChanged(this, e);
                return e.CanExecute;
            }

            return true;
        }
        #endregion
    }
}